package service

import (
	"errors"
	"fitness/go-admin/internal/config"
	"fitness/go-admin/internal/model"
	"fitness/go-admin/internal/repository"
	"fitness/go-admin/pkg/cache"
	"fitness/go-admin/pkg/utils"
	"fitness/go-admin/pkg/validator"
	"time"

	"golang.org/x/crypto/bcrypt"
	"gorm.io/gorm"
)

type AuthService interface {
	Register(req *model.RegisterReq) error
	Login(req *model.LoginReq) (*model.LoginResp, error)
	GetUserInfo(userID uint) (*model.UserInfo, error)
	ChangePassword(userID uint, req *model.ChangePasswordReq) error
	UpdateProfile(userID uint, req *model.UpdateProfileReq) error
	CheckPermission(userID uint, permission string) (bool, error)
	RefreshToken(req *model.RefreshTokenReq) (*model.RefreshTokenResp, error)
}

type authService struct {
	userRepo repository.UserRepository
	roleRepo repository.RoleRepository
}

func NewAuthService(userRepo repository.UserRepository, roleRepo repository.RoleRepository) AuthService {
	return &authService{
		userRepo: userRepo,
		roleRepo: roleRepo,
	}
}

// Register 用户注册
func (s *authService) Register(req *model.RegisterReq) error {
	// 验证用户名格式
	if err := validator.ValidateUsername(req.Username); err != nil {
		return err
	}

	// 验证密码强度
	if err := validator.ValidatePassword(req.Password); err != nil {
		return err
	}

	// 验证邮箱格式
	if err := validator.ValidateEmail(req.Email); err != nil {
		return err
	}

	// 验证手机号格式
	if err := validator.ValidatePhone(req.Phone); err != nil {
		return err
	}

	// 检查用户名是否已存在
	if existing, err := s.userRepo.GetByUsername(req.Username); err == nil && existing != nil {
		return errors.New("用户名已存在")
	}

	// 检查邮箱是否已存在
	if existing, err := s.userRepo.GetByEmail(req.Email); err == nil && existing != nil {
		return errors.New("邮箱已被注册")
	}

	// 检查手机号是否已存在
	if existing, err := s.userRepo.GetByPhone(req.Phone); err == nil && existing != nil {
		return errors.New("手机号已被注册")
	}

	// 加密密码
	hashedPassword, err := bcrypt.GenerateFromPassword([]byte(req.Password), bcrypt.DefaultCost)
	if err != nil {
		return errors.New("密码加密失败")
	}

	// 创建用户
	user := &model.User{
		Username: req.Username,
		Password: string(hashedPassword),
		Email:    req.Email,
		Phone:    req.Phone,
		Nickname: req.Nickname,
		RoleID:   3, // 默认普通用户角色
		Status:   1,
		// 不设置LastLogin字段，让它保持NULL
	}

	if user.Nickname == "" {
		user.Nickname = req.Username
	}

	return s.userRepo.Create(user)
}

// Login 用户登录
func (s *authService) Login(req *model.LoginReq) (*model.LoginResp, error) {
	// 检查登录失败次数
	if cache.RedisClient != nil && config.GlobalConfig != nil {
		// 获取登录配置
		loginConfig := config.GlobalConfig.Security.Login

		failedCount, err := cache.GetFailedLoginCount(req.Username)
		if err == nil && failedCount >= int64(loginConfig.MaxFailedAttempts) {
			return nil, errors.New("登录失败次数过多，请稍后再试")
		}
	} else if cache.RedisClient != nil {
		// 如果配置未初始化，使用默认值
		failedCount, err := cache.GetFailedLoginCount(req.Username)
		if err == nil && failedCount >= 5 {
			return nil, errors.New("登录失败次数过多，请稍后再试")
		}
	}

	// 查询用户
	user, err := s.userRepo.GetByUsername(req.Username)
	if err != nil {
		if err == gorm.ErrRecordNotFound {
			// 记录登录失败
			if cache.RedisClient != nil {
				var lockoutDuration time.Duration = 15 * time.Minute
				if config.GlobalConfig != nil {
					loginConfig := config.GlobalConfig.Security.Login
					lockoutDuration = loginConfig.LockoutDuration
				}
				cache.RecordFailedLogin(req.Username, lockoutDuration)
			}
			return nil, errors.New("用户名或密码错误")
		}
		return nil, err
	}

	// 检查用户状态
	if user.Status == 0 {
		return nil, errors.New("账号已被禁用")
	}

	// 验证密码
	if err := bcrypt.CompareHashAndPassword([]byte(user.Password), []byte(req.Password)); err != nil {
		// 记录登录失败
		if cache.RedisClient != nil {
			var lockoutDuration time.Duration = 15 * time.Minute
			if config.GlobalConfig != nil {
				loginConfig := config.GlobalConfig.Security.Login
				lockoutDuration = loginConfig.LockoutDuration
			}
			cache.RecordFailedLogin(req.Username, lockoutDuration)
		}
		return nil, errors.New("用户名或密码错误")
	}

	// 清除登录失败记录
	if cache.RedisClient != nil {
		cache.ClearFailedLogin(req.Username)
	}

	// 生成 Access Token 和 Refresh Token
	accessToken, err := utils.GenerateToken(user.ID)
	if err != nil {
		return nil, errors.New("生成Token失败")
	}

	refreshToken, err := utils.GenerateRefreshToken(user.ID)
	if err != nil {
		return nil, errors.New("生成RefreshToken失败")
	}

	// 更新最后登录时间
	now := time.Now()
	_ = s.userRepo.UpdateLastLogin(user.ID)

	// 获取角色信息
	_, role, _ := s.userRepo.GetUserWithRole(user.ID)
	roleName := "user"
	if role != nil {
		roleName = role.Code
	}

	// 构造响应
	resp := &model.LoginResp{
		AccessToken:  accessToken,
		RefreshToken: refreshToken,
		User: &model.UserInfo{
			ID:        user.ID,
			Username:  user.Username,
			Email:     user.Email,
			Phone:     user.Phone,
			Nickname:  user.Nickname,
			Avatar:    user.Avatar,
			Role:      roleName,
			RoleID:    user.RoleID,
			LastLogin: &now, // 设置登录时间
		},
		ExpiresAt: time.Now().Add(2 * time.Hour), // 与配置保持一致
	}

	return resp, nil
}

// GetUserInfo 获取用户信息
func (s *authService) GetUserInfo(userID uint) (*model.UserInfo, error) {
	user, role, err := s.userRepo.GetUserWithRole(userID)
	if err != nil {
		return nil, errors.New("用户不存在")
	}

	roleName := "user"
	if role != nil {
		roleName = role.Code
	}

	return &model.UserInfo{
		ID:        user.ID,
		Username:  user.Username,
		Email:     user.Email,
		Phone:     user.Phone,
		Nickname:  user.Nickname,
		Avatar:    user.Avatar,
		Role:      roleName,
		RoleID:    user.RoleID,
		LastLogin: user.LastLogin,
	}, nil
}

// ChangePassword 修改密码
func (s *authService) ChangePassword(userID uint, req *model.ChangePasswordReq) error {
	// 验证新密码强度
	if err := validator.ValidatePassword(req.NewPassword); err != nil {
		return err
	}

	user, err := s.userRepo.GetByID(userID)
	if err != nil {
		return errors.New("用户不存在")
	}

	// 验证旧密码
	if err := bcrypt.CompareHashAndPassword([]byte(user.Password), []byte(req.OldPassword)); err != nil {
		return errors.New("原密码错误")
	}

	// 加密新密码
	hashedPassword, err := bcrypt.GenerateFromPassword([]byte(req.NewPassword), bcrypt.DefaultCost)
	if err != nil {
		return errors.New("密码加密失败")
	}

	// 更新密码
	user.Password = string(hashedPassword)
	return s.userRepo.Update(user)
}

// UpdateProfile 更新个人资料
func (s *authService) UpdateProfile(userID uint, req *model.UpdateProfileReq) error {
	user, err := s.userRepo.GetByID(userID)
	if err != nil {
		return errors.New("用户不存在")
	}

	// 更新资料
	if req.Nickname != "" {
		user.Nickname = req.Nickname
	}
	if req.Email != "" {
		// 检查邮箱是否已被其他用户使用
		if existing, err := s.userRepo.GetByEmail(req.Email); err == nil && existing != nil && existing.ID != userID {
			return errors.New("邮箱已被其他用户使用")
		}
		user.Email = req.Email
	}
	if req.Phone != "" {
		// 检查手机号是否已被其他用户使用
		if existing, err := s.userRepo.GetByPhone(req.Phone); err == nil && existing != nil && existing.ID != userID {
			return errors.New("手机号已被其他用户使用")
		}
		user.Phone = req.Phone
	}
	if req.Avatar != "" {
		user.Avatar = req.Avatar
	}

	return s.userRepo.Update(user)
}

// CheckPermission 检查用户权限
func (s *authService) CheckPermission(userID uint, permission string) (bool, error) {
	// TODO: 实现权限检查逻辑
	return true, nil
}

// RefreshToken 刷新Token
func (s *authService) RefreshToken(req *model.RefreshTokenReq) (*model.RefreshTokenResp, error) {
	// 验证RefreshToken
	claims, err := utils.ParseRefreshToken(req.RefreshToken)
	if err != nil {
		return nil, errors.New("无效的RefreshToken")
	}

	// 生成新的Access Token
	accessToken, err := utils.GenerateToken(claims.UserID)
	if err != nil {
		return nil, errors.New("生成Token失败")
	}

	// 生成新的RefreshToken
	refreshToken, err := utils.GenerateRefreshToken(claims.UserID)
	if err != nil {
		return nil, errors.New("生成RefreshToken失败")
	}

	resp := &model.RefreshTokenResp{
		AccessToken:  accessToken,
		RefreshToken: refreshToken,
		ExpiresAt:    time.Now().Add(2 * time.Hour),
	}

	return resp, nil
}
